home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 2007 December
/
PCWKCD1207B.iso
/
Blogowanie poza sfera
/
Flock 1.0 beta
/
flock-1.0RC3.en-US.win32.exe
/
flock
/
components
/
flockPhotobucketService.js
< prev
next >
Wrap
Text File
|
2007-10-18
|
69KB
|
2,007 lines
// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2007
// http://flock.com
//
// This file may be used under the terms of of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL
const ENABLE_DEBUG = true;
function DEBUG(x) { if (ENABLE_DEBUG) debug("flockPhotobucketService: "+x+"\n"); }
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const Cu = Components.utils;
Cu.import("resource:///modules/FlockCryptoHash.jsm");
const PHOTOBUCKET_TITLE = "PhotoBucket Web Service";
const PHOTOBUCKET_FAVICON = "chrome://flock/content/services/photobucket/favicon.png";
const PHOTOBUCKET_CID = Components.ID('{d3b147b0-a321-11da-a746-0800200c9a66}');
const PHOTOBUCKET_CONTRACTID = "@flock.com/?photo-api-photobucket;1";
const SERVICE_ENABLED_PREF = "flock.service.photobucket.enabled";
const CATEGORY_COMPONENT_NAME = "Photobucket JS Component"
const CATEGORY_ENTRY_NAME = "photobucket"
const flockIError = Components.interfaces.flockIError;
const flockIPhotoAlbum = Components.interfaces.flockIPhotoAlbum;
const flockIPhotoPerson = Components.interfaces.flockIPhotoPerson;
const FLOCK_PHOTO_ALBUM_CONTRACTID = "@flock.com/photo-album;1";
const FLOCK_PHOTOPERSON_CONTRACTID = "@flock.com/photo-person;1";
const FLOCK_ERROR_CONTRACTID = "@flock.com/error;1";
const PHOTOBUCKET_API_VERSION = "1.0";
const PHOTOBUCKET_TOKEN_PREF = "flock.photo.photobucket.token";
const PHOTOBUCKET_SESSION_REFRESH_INTERVAL = 21600000; // every 6 hours refresh the session token
const PHOTOBUCKET_PK = "e57335b0847da8b1105b6c8bc27d217a";
const PHOTOBUCKET_SCID = "149825788";
const PHOTOBUCKET_PROPERTIES = "chrome://flock/locale/services/photobucket.properties";
// services
const RDFS = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
const IOS = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
const RDFCU = Cc["@mozilla.org/rdf/container-utils;1"].getService(Ci.nsIRDFContainerUtils);
var gCompTK;
function getCompTK() {
if (!gCompTK) {
gCompTK = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://browser/content/flock/services/common/load-compTK.js")
.wrappedJSObject;
}
return gCompTK;
}
// for Cardinal to Danphe migration
const FLOCK_NS = "http://flock.com/rdf#";
// String defaults... may be updated later through Web Detective
var gStrings = {
"domains": "photobucket.com",
"userloginURL": "http://photobucket.com/login.php",
"userprofileURL": "http://photobucket.com/images/search/%accountid%",
"serviceloginURL": "http://photobucket.com/svc/servicelogin.php",
"apiURL": "http://photobucket.com/svc/api.php"
};
var gPhotobucketAPI;
// ====================================================
// ========== BEGIN General Helper Functions ==========
// ====================================================
function loadSubScript(spec)
{
var loader = Components.classes['@mozilla.org/moz/jssubscript-loader;1']
.getService(Components.interfaces.mozIJSSubScriptLoader);
var context = {};
loader.loadSubScript(spec, context);
return context;
}
function loadLibraryFromSpec(aSpec) {
var loader = Components.classes["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Components.interfaces.mozIJSSubScriptLoader);
loader.loadSubScript(aSpec);
}
loadLibraryFromSpec("chrome://flock/content/common/flocksafe.js");
loadLibraryFromSpec("chrome://browser/content/flock/photo/photoAPI.js");
function photobucketPhoto() {
}
photobucketPhoto.prototype= {
id: "",
thumbnail: "",
webPageUrl: "",
midSizePhoto: "",
largeSizePhoto: "",
title: "",
username: "",
userid: "",
is_video: "",
svcShortName: 'photobucket',
buildTooltip: function( ) {
// do we have to use document from the window to ceate elements? -- ja
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var win = wm.getMostRecentWindow('navigator:browser');
if (!win) return null;
var hbox = win.document.createElement('hbox');
var box = win.document.createElement('vbox');
box.setAttribute('style', 'max-width: 250px');
var title = win.document.createElement('label');
title.setAttribute('value', this.title );
title.setAttribute('crop', 'end');
box.appendChild(title);
var lbl = win.document.createElement('label');
lbl.setAttribute('value', this.username );
lbl.setAttribute('class', 'user');
box.appendChild(lbl);
hbox.appendChild(box)
var vbox = win.document.createElement('vbox');
var cbox = win.document.createElement('hbox');
var largeImg = win.document.createElement('image');
largeImg.setAttribute('src', this.midSizePhoto);
largeImg.setAttribute('style', 'margin-bottom: 2px;');
var spacer = win.document.createElement('spacer');
spacer.setAttribute('flex', '1');
cbox.appendChild(largeImg);
cbox.appendChild(spacer);
vbox.appendChild(cbox);
vbox.appendChild(hbox);
return vbox;
},
buildHTML: function( ) {
return '<a title="'+this.title+'" href="'+this.webPageUrl+'"><img src="'+this.midSizePhoto+'" border="0" /></a>';
},
buildLargeHTML: function( ) {
return '<a title="'+this.title+'" href="'+this.webPageUrl+'"><img src="'+this.largeSizePhoto+'" border="0" /></a>';
},
buildBBCode: function ( ) {
if(this.is_video)
{
return '[photob]' + this.largeSizePhoto + '[photob]'
}else
{
return '[url=' + this.webPageUrl + '][img]'+ this.largeSizePhoto +'[/img][/url]';
}
},
buildMiniPage: function ( ) {
return '<html><head><title>' + this.title + ' (' + this.username + ')</title></head>' +
'<body><object width="425" height="350">' +
'<param name="movie" value="'+this.largeSizePhoto+'"/>' +
'<center><embed src="'+this.largeSizePhoto+'&autoplay=1" type="application/x-shockwave-flash" width="425" height="350"/></object></center></body></html>';
},
QueryInterface: function(iid) {
if (!iid.equals(Components.interfaces.nsISupports) &&
!iid.equals(Components.interfaces.flockIPhoto)) {
throw Components.results.NS_ERROR_NO_INTERFACE;
}
return this;
}
};
// ====================================================
// ========== BEGIN photobucketService class ==========
// ====================================================
function photobucketService()
{
this.obs = Components.classes["@mozilla.org/observer-service;1"]
.getService(Components.interfaces.nsIObserverService);
this.acUtils = Components.classes["@flock.com/account-utils;1"]
.getService(Components.interfaces.flockIAccountUtils);
this.url = "http://www.photobucket.com";
this.initialized = false;
this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
this.logger.init("photobucket");
this._ctk = {
interfaces: [
"nsISupports",
"nsIClassInfo",
"nsISupportsCString",
"nsIObserver",
"flockIPollingService",
"flockIWebService",
"flockIAuthenticateNewAccount",
"flockIManageableWebService",
"flockIMediaWebService"
],
shortName: "photobucket",
fullName: "Photobucket",
description: PHOTOBUCKET_TITLE,
favicon: PHOTOBUCKET_FAVICON,
contractID: PHOTOBUCKET_CONTRACTID,
accountClass: photobucketAccount,
needPassword: false
};
var sbs = Components.classes["@mozilla.org/intl/stringbundle;1"]
.getService(Components.interfaces.nsIStringBundleService);
var bundle = sbs.createBundle(PHOTOBUCKET_PROPERTIES);
this._channels = {
"special:recent": {
title: bundle.GetStringFromName("flock.photobucket.title.recent"),
supportsSearch: false
}
};
this.init();
}
// BEGIN nsIObserver interface
photobucketService.prototype.observe =
function photobucketService_observe(aSubject, aTopic, aData)
{
}
// END nsIObserver interface
photobucketService.prototype.shortName = "photobucket";
photobucketService.prototype.serviceName = "Photobucket";
photobucketService.prototype.getPhotoFromRDFNode =
function (aRDFId)
{
var newPhoto = new photobucketPhoto();
var coopPhoto = this.faves_coop.get(aRDFId);
newPhoto.webPageUrl = coopPhoto.URL;
newPhoto.thumbnail = coopPhoto.thumbnail;
newPhoto.midSizePhoto = coopPhoto.midSizePhoto;
newPhoto.largeSizePhoto = coopPhoto.largeSizePhoto;
newPhoto.username = coopPhoto.username;
newPhoto.userid = coopPhoto.userid;
newPhoto.title = coopPhoto.name;
newPhoto.id = coopPhoto.photoid;
newPhoto.icon = coopPhoto.favicon;
newPhoto.uploadDate = coopPhoto.datevalue;
newPhoto.is_public = coopPhoto.is_public;
newPhoto.is_video = coopPhoto.is_video;
return newPhoto;
}
photobucketService.prototype.handlePhotosResult =
function photobucketService_handlePhotosResult(aXML) {
var inst = this;
function createItem(media, is_video) {
var uploadDate = media.getAttribute("uploaddate");
var title = media.getAttribute("name");
var username = media.getAttribute("username");
var page_url = "";
var thumb_url = media.getElementsByTagName('thumb')[0].firstChild.nodeValue;
var small_url = media.getElementsByTagName('url')[0].firstChild.nodeValue;
// this is a photobucket api issue - need a fix -
try {
page_url = media.getElementsByTagName('browseurl')[0].firstChild.nodeValue;
page_url = page_url.replace('&', '&');
}
catch(e) {
page_url = small_url;
}
var newPhoto = new photobucketPhoto();
newPhoto.webPageUrl = page_url;
newPhoto.thumbnail = thumb_url;
newPhoto.midSizePhoto = thumb_url;
newPhoto.largeSizePhoto = small_url;
newPhoto.title = title;
newPhoto.username = username;
newPhoto.userid = username;
if (uploadDate) {
newPhoto.id = uploadDate;
newPhoto.uploadDate = parseInt(uploadDate)*1000;
} else {
newPhoto.id = username + ":" + title;
}
newPhoto.is_video = is_video;
newPhoto.has_miniView = is_video;
return newPhoto;
}
try {
var rval = [];
var videoList = aXML.getElementsByTagName("video");
for (var i = 0; i < videoList.length; i++) {
rval.push(createItem(videoList[i], true));
}
var photoList = aXML.getElementsByTagName("photo");
for (var i = 0; i < photoList.length; i++) {
rval.push(createItem(photoList[i], false));
}
} catch(e) {
inst.logger.error(e);
}
/*
* do not sort anymore since PB no longer passes back the uploadDate.
* instead we just present the photos in the order PB gives them to
* us (upload order)
* see https://bugzilla.flock.com/show_bug.cgi?id=9084
// sort the photos and videos together by date
// the follow sorts based on ID which we are using the uploadDate to be the id
// it is ugly -- and probably not as efficient as it could be --- but it
// is only sorting 20 items at most so it is good enough for now - ja
rval.sort(function(a,b) {
return (b.id-a.id);
});
*/
return rval;
}
photobucketService.prototype.getContacts =
function photobucketService_getContacts(aListener)
{
return -1; // throw unsupported exception
}
photobucketService.prototype.findByUsername =
function photobucketService_findByUsername(aListener, aUsername)
{
var inst = this;
var myListener = {
onResult: function (aXML) {
//var user = aXML.getElementsByTagName("photo")[0];
// We should be getting all the user's details from the response xml, but
// the pbucket response has all pertinent info with the photo tag. If
// there are no photos, then we have no user info
var newUserObj = Components.classes[FLOCK_PHOTOPERSON_CONTRACTID]
.createInstance(flockIPhotoPerson);
newUserObj.id = aUsername;
newUserObj.username = aUsername;
newUserObj.fullname = aUsername;
newUserObj.service = inst;
aListener.onFindByUsernameResult(newUserObj);
},
onError: function (aXML) {
aListener.onError(aXML);
}
}
var params = {};
params.username = aUsername;
var dict = params2Dictionary(params);
this.api.authenticatedCall(myListener, "getrecentusermedia", dict);
}
function MultiGetter() {
}
MultiGetter.prototype = {
mTimer: Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer),
init: function(aSvc, aListener, aEnumerator) {
this.mHasNew = false;
this.mNeedSave = false;
this.mSvc = aSvc;
this.mListener = aListener;
this.mArray = new Array();
while (aEnumerator.hasMoreElements()) {
var p = aEnumerator.getNext();
p.QueryInterface(Components.interfaces.flockIPhotoPerson);
this.mArray.push(p);
}
this.next();
},
finish: function() {
//dump("FINITI\n");
if (this.mHasNew) {
this.mListener.onGetMostRecentPhotoForList(Components.interfaces.flockIPhotoAPIListener.LIST_HAS_NEW);
}
else if (this.mNeedSave) {
this.mListener.onGetMostRecentPhotoForList(Components.interfaces.flockIPhotoAPIListener.LIST_NEED_SAVE);
}
else {
this.mListener.onGetMostRecentPhotoForList(Components.interfaces.flockIPhotoAPIListener.LIST_NO_CHANGE);
}
return;
},
updatePerson: function(aPerson, aPhoto) {
//dump(aPerson.username + "updating person\n");
var seq = aPerson.seq;
var newSeq = parseInt(aPhoto.id);
if (newSeq > seq) {
var oldHasNew = aPerson.hasNew;
aPerson.seq = aPhoto.id;
this.mNeedSave = true;
if (seq != 0) {
this.mHasNew = true;
aPerson.hasNew = true
if (oldHasNew == false) {
aPerson.lastNewSeq = seq + 1;
}
}
}
},
notify: function() {
this.doNext();
},
next: function() {
this.mTimer.initWithCallback(this, 1000, 0);
},
doNext: function() {
//dump("NEXT PLEASE\n");
var inst = this;
if (!this.mArray.length) {
this.finish();
return;
}
var person = this.mArray.pop();
var listener = {
onSearchResult: function(aEnumerator) {
//dump("b search result\n");
while (aEnumerator.hasMoreElements()) {
var photo = aEnumerator.getNext();
inst.updatePerson(person, photo);
break;
}
inst.next();
},
onError: function(aError) {
//dump("b search eror\n");
inst.finish();
}
}
this.mSvc.search(listener, person.id, "", "", 1, 1);
}
}
photobucketService.prototype.getMostRecentPhotoForList =
function photobucketService_getMostRecentPhotoForList(aListener, aEnumerator)
{
var mg = new MultiGetter();
mg.init(this, aListener, aEnumerator);
}
photobucketService.prototype.supportsSearch =
function photobucketService_supportsSearch( aQueryString ) {
var aQuery = new queryHelper(aQueryString);
if (aQuery.special) {
var channel = this._channels["special:" + aQuery.special];
if (channel) {
return channel.supportsSearch;
}
}
if (aQuery.user)
return true;
if (aQuery.search)
return false;
return null;
}
photobucketService.prototype.queryChannel =
function photobucketService_queryChannel(aListener, aQueryString, aCount, aPage)
{
var aQuery = new queryHelper(aQueryString);
var inst = this;
var myListener = {
onResult: function (aXML) {
var rval = inst.handlePhotosResult(aXML);
var enum_ = {
hasMoreElements: function() {
return (rval.length > 0);
},
getNext: function() {
return rval.shift();
}
}
aListener.onSearchResult(enum_);
},
onError: function (aError) {
// if we get an error here this probably means user inputted an illegal character
// do nothign and let the "Sorry, no results found" message appear
}
}
var params = {
page: aPage,
num: aCount
}
if (aQuery.getKey('special') == 'recent') {
var dict = params2Dictionary(params);
this.api.call(myListener, "getrecentphotos", dict);
}
if (aQuery.hasKey('search')) {
// don't pass in encoded text for PB
// if an illegal char is used, we will return no results
var aText = aQuery.search;
if (aText && aText.length) {
params.query = aText.split(".")[0];
var dict = params2Dictionary(params);
this.api.call(myListener, "search", dict);
}
}
}
photobucketService.prototype.search =
function photobucketService_search(aListener, aQueryString, aCount, aPage)
{
var aQuery = new queryHelper(aQueryString);
if (!aQuery.user) {
this.queryChannel(aListener, aQueryString, aCount, aPage);
return;
}
var aUserid = aQuery.user;
var inst = this;
var myListener = {
onResult: function (aXML) {
var rval = inst.handlePhotosResult(aXML);
var enum_ = {
hasMoreElements: function() {
return (rval.length > 0);
},
getNext: function() {
return rval.shift();
}
}
aListener.onSearchResult(enum_);
},
onError: function (aError) {
aListener.onError(aError);
}
}
var params = {};
if (aUserid) {
params.username = aUserid;
params.perpage = aCount;
}
if (aQuery.search) params.query = aQuery.getEncodedKey('search').split(".")[0];
if (aPage) params.page = aPage;
if (aQuery.album) params.album_name = aQuery.album;
params.media = 'all';
var dict = params2Dictionary(params);
if (params.query != null) {
this.api.call(myListener, "search", dict);
} else if (params.username != null) {
if (params.album_name) {
this.api.authenticatedCall(myListener, "getuseralbumpaginated", dict);
}else
this.api.authenticatedCall(myListener, "getrecentusermedia", dict);
}
}
photobucketService.prototype.createAlbum =
function photobucketService_createAlbum(aListener, aPath)
{
var svc = this;
this.logger.debug("createAlbum - aPath = "+aPath);
var albumCreationListener = {
onResult: function(aXML) {
svc.logger.info(aPath + " album successfully created");
var newAlbum = Components.classes[FLOCK_PHOTO_ALBUM_CONTRACTID]
.createInstance(flockIPhotoAlbum);
var newAlbumPath;
if (params.parent_album_name) {
newAlbumPath = params.parent_album_name + params.new_album_name;
} else {
newAlbumPath = params.new_album_name;
}
newAlbum.title = newAlbumPath;
newAlbum.id = newAlbumPath;
aListener.onCreateAlbum(newAlbum);
},
onError: function(aError) {
svc.logger.error("Error in album creation");
aListener.onError(aError);
}
}
var parentDir = "";
var pathName = aPath.split('/');
var params = new Object();
params.new_album_name = pathName.pop();
var dict;
for (var i = 0; i < pathName.length; i++) {
parentDir += pathName[i] + '/';
}
if (parentDir.length) {
params.parent_album_name = parentDir;
}
dict = params2Dictionary(params);
this.api.authenticatedCall(albumCreationListener, "createalbum", dict);
}
photobucketService.prototype.handleAlbumsResult =
function photobucketService_handleAlbumsResult(aXML)
{
var rval = new Array();
var albumList = aXML.getElementsByTagName("photoalbum");
for (var i = 0; i < albumList.length; i++) {
var album = albumList[i];
var title = album.getAttribute("name");
// the first album node has no name attr, so skip it
if (!title) continue;
var username = album.getAttribute('username');
var id;
// parse out the prefix /username/
if (title.match(album.getAttribute('username')) && title != username) {
id = title.substring(username.length + 1);
var newAlbum = Components.classes[FLOCK_PHOTO_ALBUM_CONTRACTID]
.createInstance(flockIPhotoAlbum);
newAlbum.id = id;
newAlbum.title = id;
rval.push(newAlbum);
}
}
return rval;
}
photobucketService.prototype.getAccountStatus =
function photobucketService_getAccountStatus(aListener)
{
var inst = this;
var myListener = {
onResult: function(aXML) {
try {
var result = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag2);
var username = aXML.getElementsByTagName("username")[0]
.firstChild
.nodeValue;
var maxSpace = aXML.getElementsByTagName("megabytes_allowed")[0]
.firstChild
.nodeValue;
var usedSpace = aXML.getElementsByTagName("megabytes_used")[0]
.firstChild
.nodeValue;
var isPremium = aXML.getElementsByTagName("premium")[0]
.firstChild
.nodeValue;
result.setPropertyAsAString("username", username);
result.setPropertyAsAString("maxSpace", maxSpace);
result.setPropertyAsAString("usedSpace", usedSpace);
result.setPropertyAsAString("maxFileSize", "");
result.setPropertyAsAString("usageUnits", "megabytes");
result.setPropertyAsBool("isPremium", (isPremium == "1"));
aListener.onSuccess(result, "");
} catch (ex) {
inst.logger.error('getaccountstatus error :' + ex);
}
},
onError: function (aError) {
aListener.onError(aError);
}
}
var params = new Object();
var dict = params2Dictionary(params);
this.api.authenticatedCall(myListener, "getuserinfo", dict);
}
photobucketService.prototype.getAlbums =
function photobucketService_getAlbums(aListener, aUsername)
{
var inst = this;
var myListener = {
onResult: function (aXML) {
try {
var rval = inst.handleAlbumsResult(aXML);
var enum_ = {
hasMoreElements: function() {
return (rval.length > 0);
},
getNext: function() {
return rval.shift();
}
}
aListener.onGetAlbumsResult(enum_);
} catch(e) {
inst.logger.error(e);
aListener.onError(null);
}
},
onError: function (aXML) {
aListener.onError(aXML);
}
}
var params = new Object();
params.recurse = "true";
params.view = "flat"
params.media = "none";
if (aUsername) {
params.username = aUsername;
}
var dict = params2Dictionary(params);
this.api.authenticatedCall(myListener, "getuseralbum", dict);
}
photobucketService.prototype.mUploader = null;
photobucketService.prototype.icon = PHOTOBUCKET_FAVICON;
/* features for service */
photobucketService.prototype.supportsFeature =
function photobucketService_supportsFeature(aFeature)
{
var supports = {};
supports.tags = false;
supports.title = false;
supports.contacts = false;
supports.privacy = false;
supports.fileName = true;
supports.albumCreation = true;
return (supports[aFeature] == true);
}
photobucketService.prototype.mSupportsTitle = false;
photobucketService.prototype.mSupportsTags = false;
photobucketService.prototype.mSupportsContacts = false;
photobucketService.prototype.mSupportsPrivacey = false;
photobucketService.prototype.init =
function photobucketService_init()
{
if (this.initialized) return;
this.initialized = true;
DEBUG(".init()");
this.prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
if ( this.prefService.getPrefType(SERVICE_ENABLED_PREF) &&
!this.prefService.getBoolPref(SERVICE_ENABLED_PREF) )
{
DEBUG("Pref "+SERVICE_ENABLED_PREF+" set to FALSE... not initializing.");
var catMgr = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
catMgr.deleteCategoryEntry("wsm-startup", CATEGORY_COMPONENT_NAME, true);
catMgr.deleteCategoryEntry("flockWebService", CATEGORY_ENTRY_NAME, true);
catMgr.deleteCategoryEntry("flockMediaProvider", CATEGORY_ENTRY_NAME, true);
return;
}
this.mAuthUser = {};
this.faves_coop = Components.classes["@flock.com/singleton;1"]
.getService(Components.interfaces.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
this.urn = 'urn:photobucket:service';
this.pbService = new this.faves_coop.Service(
this.urn,
{
name: "photobucket",
desc: "The Photobucket Service",
contactLabel: 'People'
}
);
this.pbService.serviceId = PHOTOBUCKET_CONTRACTID;
if (!gPhotobucketAPI) {
gPhotobucketAPI = new PhotobucketAPI();
}
this.api = gPhotobucketAPI;
// Load Web Detective file
this.webDetective = this.acUtils.useWebDetective("photobucket.xml");
for (var s in gStrings) {
gStrings[s] = this.webDetective.getString("photobucket", s, gStrings[s]);
}
this.mApiUrl = gStrings["apiURL"];
this.pbService.domains = gStrings["domains"];
this.pbService.loginURL = gStrings["userloginURL"];
// Update auth states
try {
if (this.webDetective.detectCookies("photobucket", "loggedout", null)) {
this.acUtils.markAllAccountsAsLoggedOut(PHOTOBUCKET_CONTRACTID);
this.mAuthUser = null;
this.mUploader = null;
} else {
this.checkPersistedToken();
}
} catch (ex) {
this.logger.error("ERROR updating auth states for Photobucket: "+ex);
}
}
photobucketService.prototype.checkPersistedToken =
function photobucketService_checkPersistedToken()
{
var acctURN = this.acUtils.getFirstAuthenticatedAccountForService(PHOTOBUCKET_CONTRACTID);
if (!acctURN) { return; }
var token = this.faves_coop.get(acctURN).authToken;
if (token) {
this.logger.debug('checking if the session associated with the token is still valid ... ' + token);
// try to get the session from the persisted token
var inst = this;
var myListener = {
onResult: function(aXML) {
try {
var resp = aXML.getElementsByTagName('response');
if (resp[0].getAttribute('stat') == 'ok') {
var username = aXML.getElementsByTagName('username')[0].firstChild.nodeValue;
var sessionkey = aXML.getElementsByTagName('session_key')[0].firstChild.nodeValue;
inst.api.mApiUrl = aXML.getElementsByTagName("url")[0].firstChild.nodeValue;
inst.getAuthUser().id = username;
inst.getAuthUser().username = username;
inst.getAuthUser().fullname = username;
inst.getAuthUser().sessionkey = sessionkey;
if (!inst.api.mSessionRefreshTimer) inst.api.fireSessionRefreshTimer();
} else {
inst.mAuthUser = null;
this.mUploader = null;
}
}
catch(e) {
inst.logger.error(e);
}
},
onError: function(aErr) {
return false;
}
}
var params = {};
params.service_token = token;
inst.call(myListener, "getsession", params2Dictionary(params));
}
//this.mAuthUser.sessionkey = null;
}
photobucketService.prototype.getAuthState =
function photobucketService_getAuthState()
{
return this.state;
}
photobucketService.prototype.__defineGetter__("supportsTitle", function () { return this.mSupportsTitle; })
photobucketService.prototype.__defineGetter__("supportsTags", function () { return this.mSupportsTags; })
photobucketService.prototype.__defineGetter__("supportsContacts", function () { return this.mSupportsContacts; })
photobucketService.prototype.__defineGetter__("supportsPrivacey", function () { return this.mSupportsPrivacey; })
photobucketService.prototype.__defineGetter__("authState", function () { return this.state; })
photobucketService.prototype.logout =
function photobucketService_logout()
{
this.mAuthUser = null;
this.mUploader = null;
if (this.mSessionRefreshTimer) { this.mSessionRefreshTimer.cancel(); }
this.acUtils.removeCookies(this.webDetective.getSessionCookies("photobucket"));
}
photobucketService.prototype.getAuthUser =
function photobucketService_getAuthUser()
{
return this.api.mAuthUser;
}
photobucketService.prototype.getAuthPerson =
function photobucketService_getAuthPerson()
{
var user = this.getAuthUser();
if (!user) {
return null;
}
var person = {};
person.id = user.id;
person.fullname = user.fullname;
person.username = user.username;
person.service = this;
return person;
}
photobucketService.prototype.notify = function photobucketService_sessionTimerNotify(aTimer) {
var inst = this;
var sessionRefreshListener = {
onAuth: function() {
inst.logger.debug('yay! pbucket refreshed its session key with the timer');
},
onError: function(aError) {
inst.logger.error('!!!boo! error refreshing session key on the timer');
}
}
this.getSessionKey(sessionRefreshListener);
}
photobucketService.prototype.getSessionKey =
function photobucketService_getSessionKey(aListener)
{
var acctURN = this.acUtils.getFirstAuthenticatedAccountForService(PHOTOBUCKET_CONTRACTID);
if (!acctURN) aListener.onError(null);
var token = this.faves_coop.get(acctURN).token;
this.logger.debug(">>>getSessionKey called with the token "+token+"\n\n\n");
var inst = this;
var mySessionListener = {
onResult: function(aXML) {
var username = aXML.getElementsByTagName('username')[0].firstChild.nodeValue;
var sessionkey = aXML.getElementsByTagName('session_key')[0].firstChild.nodeValue;
inst.api.mApiUrl = aXML.getElementsByTagName('url')[0].firstChild.nodeValue;
inst.getAuthUser().id = username;
inst.getAuthUser().username = username;
inst.getAuthUser().fullname = username;
inst.getAuthUser().sessionkey = sessionkey;
aListener.onAuth();
},
onError: function(aErr) {
inst.logger.debug('>>>>>> ' + aErr.errorString + '\n\n')
aListener.onError(aErr);
}
};
var params = {};
params.service_token = token;
inst.call(mySessionListener, "getsession", params2Dictionary(params));
}
photobucketService.prototype.upload =
function photobucketService_upload(aListener, aUpload, aFile)
{
var inst = this;
var sigParams = {};
var myParams = {};
this.logger.debug('uploading to album ' + aUpload.album);
myParams.version = PHOTOBUCKET_API_VERSION;
myParams.scid = PHOTOBUCKET_SCID;
myParams.method = 'upload';
myParams.description = aUpload.description;
myParams.title = aUpload.title;
myParams.album_name = aUpload.album;
myParams.session_key = this.getAuthUser().sessionkey;
myParams.sig = this.api.buildSig("upload", sigParams, true);
sigParams.session_key = this.getAuthUser().sessionkey;
this.mUploader = new PhotoUploader();
this.mUploader.setEndpoint(inst.api.mApiUrl);
this.mUploader.photoParam = "uploadfile";
var myListener = {
onResult: function(aXML) {
var photo = aXML.getElementsByTagName("photo")[0];
if (photo) {
inst.logger.debug('uploaded the pic named ' + photo.getAttribute('name'));
var rval = inst.handlePhotosResult(aXML);
aListener.onUploadComplete(aUpload);
aListener.onUploadFinalized(aUpload, rval[0]);
}
else {
aListener.onError(inst.api.getError("SERVICE_ERROR", aXML, null));
}
},
onError: function(aErrorCode) {
if (aErrorCode) {
aListener.onError(inst.api.getError("HTTP_ERROR", null, aErrorCode));
} else {
aListener.onError(inst.api.getError("SERVICE_ERROR", null, null));
}
},
onProgress: function(aCurrentProgress) {
aListener.onProgress(aCurrentProgress);
}
}
this.mUploader.upload(myListener, aFile, myParams, aUpload);
}
photobucketService.prototype.cancelUpload =
function photobucketService_cancelUpload()
{
try {
this.mUploader.req.abort();
} catch(e) { }
}
// flockIPollingService implementation
photobucketService.prototype.refresh =
function photobucketService_refresh(aURN, aListener)
{
var refreshItem = this.faves_coop.get(aURN);
if (refreshItem.isInstanceOf(this.faves_coop.Account)) {
aListener.onResult();
}
}
photobucketService.prototype.migrateAccount =
function photobucketService_migrateAccount( aId, aUsername) {
this.init();
var token = '';
try {
token = flock_getCharPref(PHOTOBUCKET_TOKEN_PREF);
} catch (e) { }
this.addAccountById(aId, false, null, aUsername, token);
}
// BEGIN flockIWebService interface
photobucketService.prototype.addAccountById =
function photobucketService_addAccountById(aAccountID, aIsTransient, aListener, aUsername, aToken)
{
this.logger.debug("{flockIWebService}.addAccountById('"+aAccountID+"', "+aIsTransient+", aListener)");
if (!aUsername) {
// Get the password associated with this account
var pw = this.acUtils.getPassword(this.urn+':'+aAccountID);
var name = pw.user;
var token = '';
var pollable = false;
var auth = false;
} else {
var name = aUsername;
var token = aToken;
var pollable = true;
var auth = true;
}
var accountURN = "urn:flock:photobucket:"+aAccountID;
var acctCoopObj = this.faves_coop.get(accountURN);
if (!acctCoopObj) {
acctCoopObj = new this.faves_coop.Account(
accountURN,
{
accountId: aAccountID,
name: name, // This gets changed to the user's full name once logged in
serviceId: PHOTOBUCKET_CONTRACTID,
service: this.pbService,
URL: "http://www.photobucket.com/",
favicon: this.icon,
isTransient: aIsTransient,
isPollable: pollable,
authToken: token,
isAuthenticated: auth
}
);
this.faves_coop.accounts_root.children.add(acctCoopObj);
}
// perhaps we should do a checktoken and if valid go ahead and set the account as logged in?
var acct = this.getAccount(acctCoopObj.id());
if (aListener) aListener.onSuccess(acct, "addAccount");
return acct;
}
// END flockIWebService interface
// BEGIN flockIAuthenticateNewAccount interface
photobucketService.prototype.authenticateNewAccount =
function photobucketService_authenticateNewAccount(aListener)
{
this.logger.debug("{flockIAuthenticateNewAccount}.authenticateNewAccount(aListener)");
aListener.onStart(null, "newaccountstarted");
var inst = this;
var tokenListener = {
onResult: function (aXML) {
inst.logger.debug(".authenticateNewAccount(): tokenListener: onResult()");
var params = {
service_token: aXML.getElementsByTagName("service_token")[0].firstChild.nodeValue
};
var sessionListener = {
onResult: function (aXML) {
inst.logger.debug(".authenticateNewAccount(): tokenListener: sessionListener: onResult()");
var username = aXML.getElementsByTagName("username")[0].firstChild.nodeValue;
var sessionkey = aXML.getElementsByTagName("session_key")[0].firstChild.nodeValue;
inst.api.mApiUrl = aXML.getElementsByTagName("url")[0].firstChild.nodeValue;
inst.getAuthUser().id = username;
inst.getAuthUser().username = username;
inst.getAuthUser().fullname = username;
inst.getAuthUser().sessionkey = sessionkey;
var acctURN = inst.acUtils.getFirstAuthenticatedAccountForService(PHOTOBUCKET_CONTRACTID);
var account = null;
try {
account = inst.getAccount(acctURN);
if (!account) throw "ACCOUNT WAS NOT CREATED";
} catch (ex) {
dump(ex);
inst.logger.error(".authenticateNewAccount(): tokenListener: onResult(): ERROR: account was not created");
if (aListener) {
aListener.onError(null, "newaccount", null);
}
return;
}
if (aListener) {
aListener.onSuccess(account, "newaccount");
}
},
onError: function (aError) {
inst.logger.debug(".authenticateNewAccount(): tokenListener: sessionListener: onError()");
inst.logger.debug(">>>>>> " + aError.errorString);
if (aListener) {
aListener.onError(aError, "newaccount", aError);
}
}
};
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
var ww = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
.getService(Components.interfaces.nsIWindowWatcher);
var topWin = wm.getMostRecentWindow(null);
var loginUrl = inst.api.buildUrl(gStrings["serviceloginURL"], "login", params);
var url = "chrome://browser/content/flock/photo/photoLoginWindow.xul?"
+ "url="+escape(loginUrl)
+ "&finalString="+escape("You have granted");
var chrome = "chrome,close,titlebar,resizable=yes,toolbar,dialog=no,"
+ "scrollbars=yes,modal,centerscreen";
topWin.open(url, "_blank", chrome);
// Wait till the window closes
inst.api.call(sessionListener, "getsession", params2Dictionary(params));
},
onError: function (aError) {
inst.logger.debug(".authenticateNewAccount(): tokenListener: onError()");
inst.logger.debug(">>>>>> " + aError.errorString);
if (aListener) {
aListener.onError(aError, "newaccount");
}
}
};
if (!this.api.mAuthUser) {
this.api.mAuthUser = {};
}
this.api.getToken(tokenListener);
}
// END flockIAuthenticateNewAccount interface
// BEGIN flockIManageableWebService interface
photobucketService.prototype.getAccountIDFromDocument =
function photobucketService_getAccountIDFromDocument(aDocument)
{
this.logger.debug("{flockIManageableWebService}.getAccountIDFromDocument(aDocument)");
aDocument.QueryInterface(Components.interfaces.nsIDOMHTMLDocument);
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
if (this.webDetective.detect("photobucket", "accountinfo", aDocument, results)) {
return results.getPropertyAsAString("userid");
} else {
// We could not detect any account info on the login landing page. This
// may mean that it's the API authentication login landing page, which
// doesn't have any account info. If this is the case, then we should
// have a temp password entry associated with the session cookie.
var sessionValue = this.acUtils.getCookie("http://photobucket.com", "PHPSESSID");
var pw = this.acUtils.getTempPassword("photobucket:session:"+sessionValue);
if (pw) {
this.logger.debug("Sneaky! Got acctID from a temp password associated with session cookie!");
return pw.user;
}
}
return null;
}
photobucketService.prototype.getCredentialsFromForm =
function photobucketService_getCredentialsFromForm(aForm)
{
var inst = this;
var detectForm = function (aType, aResults) {
return inst.webDetective.detectForm("photobucket", aType, aForm, aResults);
};
var formType = "login";
var results = getCompTK().newResults();
if (!detectForm(formType, results)) {
formType = "signup";
results = getCompTK().newResults();
if (!detectForm(formType, results)) {
formType = "changepassword";
results = getCompTK().newResults();
if (!detectForm(formType, results)) {
results = null;
}
}
}
if (results) {
var pw = {
QueryInterface: function(aIID) {
if (!aIID.equals(Components.interfaces.nsISupports) &&
!aIID.equals(Components.interfaces.nsIPassword) &&
!aIID.equals(Components.interfaces.flockIPassword)) {
throw Components.interfaces.NS_ERROR_NO_INTERFACE;
}
return this;
},
user: results.getPropertyAsAString("username"),
password: results.getPropertyAsAString("password"),
host: null,
formType: formType
};
// Doing a bit of a hack here...
// Since the Photobucket login landing page doesn't always reveal which
// account is logged in, we will need to look at the session cookie and
// see if its the same as what it was when the user last logged in. So
// at this point we're just storing the account username as a temp
// password entry associated with the session cookie token.
var sessionValue = this.acUtils.getCookie("http://photobucket.com", "PHPSESSID");
this.acUtils.clearTempPassword("photobucket:session:"+sessionValue);
this.acUtils.setTempPassword("photobucket:session:"+sessionValue, pw.user, "", formType);
return pw;
}
return null;
}
photobucketService.prototype.updateAccountStatusFromDocument =
function photobucketService_updateAccountStatusFromDocument(aDocument)
{
var inst = this;
this.logger.debug("{flockIManageableWebService}.updateAccountStatusFromDocument('"+aDocument.URL+"')");
if (this.webDetective.detect("photobucket", "loggedout", aDocument, null)) {
this.acUtils.markAllAccountsAsLoggedOut(PHOTOBUCKET_CONTRACTID);
this.logout();
} else if (this.webDetective.detect("photobucket", "loggedin", aDocument, null)) {
var acctID;
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
if (this.webDetective.detect("photobucket", "accountinfo", aDocument, results)) {
acctID = results.getPropertyAsAString("userid");
} else {
// We could not detect any account info on the login landing page. This
// may mean that it's the API authentication login landing page, which
// doesn't have any account info. If this is the case, then we should
// have a temp password entry associated with the session cookie.
var sessionValue = this.acUtils.getCookie("http://photobucket.com", "PHPSESSID");
var pw = this.acUtils.getTempPassword("photobucket:session:"+sessionValue);
if (pw) {
this.logger.debug("Sneaky! Got acctID from a temp password associated with session cookie!");
acctID = pw.user;
}
}
if (acctID) {
var acctURN = this.acUtils.getAccountURNById(this.urn, acctID);
if (acctURN) {
var acctCoopObj = this.faves_coop.get(acctURN);
if (!acctCoopObj.isAuthenticated) {
// Re-authenticate the API
var reauthListener = {
onAuth: function () {
inst.logger.debug("reauthListener: onAuth()");
},
onError: function (aError) {
inst.logger.debug("reauthListener: onError()");
acctCoopObj.isAuthenticated = false;
}
};
this.getAccount(acctURN).login(reauthListener);
// Prematurely set isAuthenticated to TRUE in order to avoid other
// asyncronous auth attempts before this one completes.
acctCoopObj.isAuthenticated = true;
}
}
}
}
}
// END flockIManageableWebService interface
// BEGIN flockIMediaWebService interface
photobucketService.prototype.decorateForMedia =
function photobucketService_decorateForMedia(aDocument)
{
this.logger.debug("{flockIMediaWebService}.decorateForMedia(aDocument)");
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
if (this.webDetective.detect("photobucket", "media", aDocument, results)) {
var userid = results.getPropertyAsAString("userid");
var mediaArr = new Array();
if (!aDocument._flock_decorations) {
aDocument._flock_decorations = new Object();
}
var media = {
name: userid,
query: 'user:' + userid + "|username:" + userid,
label: userid,
favicon: this.icon,
service: this.shortName
}
mediaArr.push(media);
aDocument._flock_decorations.mediaArr = mediaArr;
this.obs.notifyObservers(aDocument, 'media', 'media:update');
}
}
photobucketService.prototype.handlesMediaStream =
function photobucketService_handlesMediaStream()
{
return true;
}
photobucketService.prototype.checkIsStreamUrl =
function photobucketService_checkIsStreamUrl(aUrl)
{
// Videos:
// /player.swf?file=http://vid166.photobucket.com/albums/u113/h671226/Smart_Dog.flv
// Images:
// http://i166.photobucket.com/albums/u105/such-a-craka/thfhg.jpg
if (this.webDetective.detectNoDOM("photobucket", "isStreamUrl", "", aUrl, null)) {
this.logger.debug("Checking if url is photobucket stream: YES: " + aUrl);
return true;
}
this.logger.debug("Checking if url is photobucket stream: NO: " + aUrl);
return false;
}
photobucketService.prototype.getMediaQueryFromURL =
function photobucketService_getMediaQueryFromURL(aUrl, aListener)
{
var userName = null;
var detectResults = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag2);
if (this.webDetective.detectNoDOM("photobucket", "person", "", aUrl, detectResults)) {
userName = detectResults.getPropertyAsAString("userid");
}
if (userName) {
var results = Components.classes["@mozilla.org/hash-property-bag;1"]
.createInstance(Components.interfaces.nsIWritablePropertyBag2);
results.setPropertyAsAString("query", "user:" + userName + "|username:" + userName);
results.setPropertyAsAString("title", this.title + " user: " + userName);
aListener.onSuccess(results, "query");
} else {
aListener.onError(null, "Unable to get user.", null);
}
}
// END flockIMediaWebService interface
photobucketService.prototype.doMigration =
function photobucketService_doMigration(aDatasource, aAccountURN) {
}
// ================================================
// ========== BEGIN XPCOM Module support ==========
// ================================================
function createModule(aParams) {
return {
registerSelf: function (aCompMgr, aFileSpec, aLocation, aType) {
aCompMgr.QueryInterface(Ci.nsIComponentRegistrar);
aCompMgr.registerFactoryLocation( aParams.CID, aParams.componentName,
aParams.contractID, aFileSpec,
aLocation, aType );
var catMgr = Cc["@mozilla.org/categorymanager;1"]
.getService(Ci.nsICategoryManager);
if (!aParams.categories) { aParams.categories = []; }
for (var i = 0; i < aParams.categories.length; i++) {
var cat = aParams.categories[i];
catMgr.addCategoryEntry( cat.category, cat.entry,
cat.value, true, true );
}
},
getClassObject: function (aCompMgr, aCID, aIID) {
if (!aCID.equals(aParams.CID)) { throw Cr.NS_ERROR_NO_INTERFACE; }
if (!aIID.equals(Ci.nsIFactory)) { throw Cr.NS_ERROR_NOT_IMPLEMENTED; }
return { // Factory
createInstance: function (aOuter, aIID) {
if (aOuter != null) { throw Cr.NS_ERROR_NO_AGGREGATION; }
var comp = new aParams.componentClass();
if (aParams.implementationFunc) { aParams.implementationFunc(comp); }
return comp.QueryInterface(aIID);
}
};
},
canUnload: function (aCompMgr) { return true; }
};
}
// NS Module entrypoint
function NSGetModule(aCompMgr, aFileSpec) {
return createModule({
componentClass: photobucketService,
CID: PHOTOBUCKET_CID,
contractID: PHOTOBUCKET_CONTRACTID,
componentName: CATEGORY_COMPONENT_NAME,
implementationFunc: function (aComp) { getCompTK().addAllInterfaces(aComp); },
categories: [
{ category: "wsm-startup", entry: CATEGORY_COMPONENT_NAME, value: PHOTOBUCKET_CONTRACTID },
{ category: "flockWebService", entry: CATEGORY_ENTRY_NAME, value: PHOTOBUCKET_CONTRACTID },
{ category: "flockMediaProvider", entry: CATEGORY_ENTRY_NAME, value: PHOTOBUCKET_CONTRACTID }
]
});
}
// ========== END XPCOM Module support ==========
// ====================================================
// ============= BEGIN photobucket API ================
// ====================================================
function PhotobucketAPI() {
this._logger = Cc["@flock.com/logger;1"]
.createInstance(Ci.flockILogger);
this._logger.init("photobucketAPI");
this._logger.info("Created Photobucket API Object");
this.acUtils = Cc["@flock.com/account-utils;1"]
.getService(Ci.flockIAccountUtils);
this.webDetective = this.acUtils.useWebDetective("photobucket.xml");
this.faves_coop = Cc["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
this.mApiUrl = gStrings["apiURL"];
this.mAuthUser = null;
this.mSessionRefreshTimer = null;
var inst = this;
};
PhotobucketAPI.prototype.isLoggedIn =
function photobucketAPI_isLoggedIn() {
return (this.mAuthUser && this.mAuthUser.sessionkey != null);
};
PhotobucketAPI.prototype.getToken =
function photobucketAPI_getToken(aListener) {
var inst = this;
var tokenListener = {
onResult: function (aXML) {
try {
var resp = aXML.getElementsByTagName("response");
if (resp[0].getAttribute("stat") == "ok") {
//rval = resp[0].firstChild.nodeValue;
aListener.onResult(aXML);
} else {
aListener.onError(null); //TODO - figure out errors
//rval = -1;
}
}
catch(e) {
inst._logger.error(e);
}
},
onError: function (aError) {
inst._logger.error(aError.errorString);
aListener.onError(aError);
}
}
var params = {};
this.call(tokenListener, "getservicetoken", params2Dictionary(params));
};
PhotobucketAPI.prototype.call =
function photobucketAPI_call(aListener,
aMethod,
aDictionary,
aAuth) {
var inst = this;
var params = this.dictionary2Params(aDictionary);
var url = this.buildUrl(inst.mApiUrl, aMethod, params, aAuth);
this._logger.debug(url + " < call");
this.req = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Ci.nsIXMLHttpRequest)
.QueryInterface(Ci.nsIJSXMLHttpRequest);
this.req.open("GET", url, true);
var req = this.req;
this.req.onreadystatechange = function (aEvt) {
if (req.readyState == 4) {
try {
inst._logger.debug("doCall[onreadystatechange] req.status = "
+ req.status);
if (req.status/100 == 2) {
inst._logger.debug(req.responseText);
var rsp = req.responseXML.getElementsByTagName("response")[0];
var stat = rsp.getAttribute("stat");
if (stat != "ok") {
aListener.onError(inst.getError("SERVICE_ERROR",
req.responseXML,
null));
} else {
aListener.onResult(req.responseXML);
}
} else {
aListener.onError(inst.getError("HTTP_ERROR", null, req.status));
}
} catch(e) {
inst._logger.error(e);
// We need to convert to a string because that's what getError expects
var errorCode = String(Ci.flockIError.XML_HTTP_REQUEST_ERROR)
aListener.onError(inst.getError("HTTP_ERROR", null, errorCode));
}
}
}
this.req.send(null);
};
PhotobucketAPI.prototype.dictionary2Params =
function photobucketAPI_dictionary2Params(aDictionary) {
var params = {};
var obj = {};
var count = {};
var keys = aDictionary.getKeys(count, obj);
for (var i = 0; i < keys.length; ++i) {
var supports = aDictionary.getValue(keys[i]);
var supportsString = supports.QueryInterface(Ci.nsISupportsString);
var val = supportsString.toString();
params[keys[i]] = val;
}
return params;
};
PhotobucketAPI.prototype.authenticatedCall =
function photobucketAPI_authenticatedCall(aListener,
aMethod,
aDictionary) {
this._logger.debug("authenticatedCall " + aMethod);
if (!this.isLoggedIn()) {
this._logger.debug("not logged in, so trying unauth call for " + aMethod);
return this.call(aListener, aMethod, aDictionary);
}
this._logger.debug("+++++" + this.mAuthUser.sessionkey);
return this.call(aListener, aMethod, aDictionary, true);
};
PhotobucketAPI.prototype.doLogin =
function photobucketAPI_doLogin(aAccountURN, aListener) {
this._logger.debug(".doLogin('" + aAccountURN + "')");
var inst = this;
var tokenListener = {
onResult: function(aXML) {
inst._logger.debug(".doLogin('"
+ aAccountURN +
"'): tokenListener: onResult()");
// Time to authenticate...
var params = {
service_token: aXML.getElementsByTagName("service_token")[0]
.firstChild
.nodeValue
};
// persist the token
var acctCoopObj = inst.faves_coop.get(aAccountURN);
acctCoopObj.authToken = params.service_token;
// listener for the upcoming "getsession" api call
var sessionListener = {
onResult: function(aXML) {
inst._logger.debug(".doLogin('"
+ aAccountURN
+ "'): tokenListener:"
+ "sessionListener: onResult()");
var username = aXML.getElementsByTagName('username')[0]
.firstChild
.nodeValue;
var sessionkey = aXML.getElementsByTagName('session_key')[0]
.firstChild
.nodeValue;
inst.mApiUrl = aXML.getElementsByTagName('url')[0]
.firstChild
.nodeValue;
inst.mAuthUser.id = username;
inst.mAuthUser.username = username;
inst.mAuthUser.fullname = username;
inst.mAuthUser.sessionkey = sessionkey;
inst.acUtils.ensureOnlyAuthenticatedAccount(aAccountURN);
if (!inst.mSessionRefreshTimer) inst.fireSessionRefreshTimer();
aListener.onSuccess(null, "");
},
onError: function(aErr) {
inst._logger.error(".doLogin('"
+ aAccountURN
+ "'): tokenListener: sessionListener: onError()");
inst._logger.error(">>>>>> " + aErr.errorString);
aListener.onError(aErr);
}
};
// If we have the user's un/pw, then we can do this silently...
var pw = inst.acUtils.getPassword("urn:photobucket:service:"
+ acctCoopObj.accountId);
if (pw) {
inst._logger.debug(".doLogin('"
+ aAccountURN
+ "'): tokenListener: onResult(): found password");
var postBody = "action=login"
+ "&service_token="+params.service_token
+ "&sig="+inst.buildSig("login", params)
+ "&scid="+PHOTOBUCKET_SCID
+ "&method=login"
+ "&callback_verify="
+ "&username="+pw.user
+ "&password="+pw.password
+ "&login=Login";
var hr = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Ci.nsIXMLHttpRequest)
.QueryInterface(Ci.nsIJSXMLHttpRequest);
var onReadyStateFunc = function(eEvt) {
if (hr.readyState == 4) {
inst._logger.debug(".doLogin('"
+ aAccountURN
+ "'): tokenListener:"
+ "onResult(): hr.onreadystatechange()");
var results = Cc["@mozilla.org/hash-property-bag;1"]
.createInstance(Ci.nsIWritablePropertyBag2);
if (inst.webDetective.detectNoDOM("photobucket",
"apiauth",
"",
hr.responseText,
results)) {
var hr2 = Cc['@mozilla.org/xmlextras/xmlhttprequest;1']
.createInstance(Ci.nsIXMLHttpRequest)
.QueryInterface(Ci.nsIJSXMLHttpRequest);
hr2.onreadystatechange = function(eEvt2) {
if (hr2.readyState == 4) {
inst.call(sessionListener,
"getsession",
params2Dictionary(params));
}
}
var postBody2 = "action=complete"
+ "&authorized=yes"
+ "&service_token=" + params.service_token
+ "&sig=" + inst.buildSig("login", params)
+ "&scid=" + PHOTOBUCKET_SCID
+ "&method=login"
+ "&callback_verify="
+ "&user_id="
+ results.getPropertyAsAString("user_id");
hr2.backgroundRequest = true;
hr2.open("POST", gStrings["serviceloginURL"],true);
hr2.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
hr2.send(postBody2);
} else {
inst.call(sessionListener,
"getsession",
params2Dictionary(params));
}
}
};
hr.onreadystatechange = onReadyStateFunc;
hr.backgroundRequest = true;
hr.open("POST", gStrings["serviceloginURL"],true);
hr.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
hr.send(postBody);
} else {
inst._logger.debug(".doLogin('"
+ aAccountURN +
"'): tokenListener: onResult(): NO password!");
// No password stored, so we have to prompt the user
var windowManager = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator);
var topWindow = windowManager.getMostRecentWindow(null);
var loginUrl = inst.buildUrl(gStrings["serviceloginURL"],
"login",
params);
var url = "chrome://browser/content/flock/photo/photoLoginWindow.xul?"
+ "url=" + escape(loginUrl)
+ "&finalString=" + escape("You have granted");
var options = "chrome,"
+ "close,"
+ "titlebar,"
+ "resizable=yes,"
+ "toolbar,"
+ "dialog=no,"
+ "scrollbars=yes,"
+ "modal,"
+ "centerscreen";
topWindow.open(url, "_blank", options);
// we are waiting till window closes
inst.call(sessionListener, "getsession", params2Dictionary(params));
}
},
onError: function(aErr) {
inst._logger.error(".doLogin('"
+ aAccountURN
+ "'): tokenListener: onError()");
aListener.onError(aErr);
}
}
if (!this.mAuthUser) {
this.mAuthUser = {};
}
this.getToken(tokenListener);
};
PhotobucketAPI.prototype.fireSessionRefreshTimer =
function photobucketAPI_fireSessionRefreshTimer() {
this.mSessionRefreshTimer = Cc["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
// refresh the session key once an hour, probably can adjust this
this.mSessionRefreshTimer.initWithCallback(this,
PHOTOBUCKET_SESSION_REFRESH_INTERVAL,
2);
};
PhotobucketAPI.prototype.getError =
function photobucketAPI_getError(aErrorType, aXML, aHTTPErrorCode) {
var errorNode;
var code;
var serverErrorMessage;
var error = Cc[FLOCK_ERROR_CONTRACTID]
.createInstance(flockIError);
this._logger.debug("getError aErrorType="
+ aErrorType
+ "; aHTTPErrorCode="
+ aHTTPErrorCode);
if (aErrorType == "HTTP_ERROR") {
error.errorCode = aHTTPErrorCode;
return error;
} else if (aErrorType == "SERVICE_ERROR") {
try {
errorNode = aXML.getElementsByTagName("error")[0];
code = errorNode.getAttribute("code");
serverErrorMessage = errorNode.getAttribute("msg");
error.serviceErrorCode = code;
error.serviceErrorString = serverErrorMessage;
this._logger.debug("Found error code = "
+ code
+ " and message = '"
+ serverErrorMessage
+ "'");
} catch (ex) {
code = "-1"
}
if (!code) code = "-1";
switch (code) {
case "-1":
error.errorCode = error.PHOTOSERVICE_INVALID_RESPONSE;
break;
case "007":
case "008":
error.errorCode = error.PHOTOSERVICE_LOGIN_FAILED;
break;
case "012":
error.errorCode = error.PHOTOSERVICE_SESSION_KEY_EXPIRED;
break;
case "101":
error.errorCode = error.PHOTOSERVICE_EMPTY_ALBUMNAME;
break;
case "102":
error.errorCode = error.PHOTOSERVICE_INVALID_USER;
break;
case "103":
error.errorCode = error.PHOTOSERVICE_INVALID_SEARCH_QUERY;
break;
case "104":
error.errorCode = error.PHOTOSERVICE_INVALID_SEARCH_QUERY;
break;
case "105":
error.errorCode = error.PHOTOSERVICE_INVALID_UPLOAD_FILE;
break;
case "106":
error.errorCode = error.PHOTOSERVICE_INVALID_SEARCH_QUERY;
break;
case "107":
error.errorCode = error.PHOTOSERVICE_INVALID_ALBUM;
break;
case "108":
error.errorCode = error.PHOTOSERVICE_PRIVATE_ALBUM;
break;
case "109":
error.errorCode = error.PHOTOSERVICE_PHOTOS_IN_ALBUM_LIMIT_REACHED;
break;
case "110":
error.errorCode = error.PHOTOSERVICE_NO_FILE_UPLOADED;
break;
case "111":
error.errorCode = error.PHOTOSERVICE_ALBUM_IS_OVER_SIZE_LIMIT;
break;
case "112":
error.errorCode = error.PHOTOSERVICE_INVALID_UPLOAD_FILE;
break;
case "113":
error.errorCode = error.PHOTOSERVICE_DUPLICATE_FILENAME;
break;
case "115":
error.errorCode = error.PHOTOSERVICE_INVALID_ALBUMNAME;
break;
case "116":
error.errorCode = error.PHOTOSERVICE_DUPLICATE_ALBUMNAME;
break;
case "314":
error.errorCode = error.PHOTOSERVICE_FILE_IS_OVER_SIZE_LIMIT;
break;
default:
error.errorCode = error.PHOTOSERVICE_UNKNOWN_ERROR;
if (serverErrorMessage && serverErrorMessage.length) {
error.serviceErrorString = serverErrorMessage;
}
break;
}
return error;
}
return null;
};
PhotobucketAPI.prototype.buildUrl =
function photobucketAPI_buildUrl(aUrl, aMethod, aParams, aAuth) {
var qs = "";
var strConcat = "";
for (var p in aParams) {
qs += "&" + escape(p) + "=" + escape(aParams[p]);
strConcat += escape(aParams[p]);
}
var rval = aUrl
+ "?method=" + aMethod
+ "&version=" + PHOTOBUCKET_API_VERSION;
if (aAuth) {
rval += "&session_key=" + this.mAuthUser.sessionkey;
}
rval += "&scid=" + PHOTOBUCKET_SCID
+ qs
+ "&sig=" + this.buildSig(aMethod, aParams, aAuth);
this._logger.debug("this is your buildUrl: " + rval + "\n");
return rval;
};
PhotobucketAPI.prototype.buildSig =
function photobucketAPI_buildSig(aMethod, aParams, aAuth) {
var qs = "";
var strConcat = "";
for (var p in aParams) {
qs += "&" + escape(p) + "=" + escape(aParams[p]);
if (p == 'service_token') {
strConcat += escape(aParams[p]);
}
}
this._logger.debug(strConcat + "<<<<<<<<strconcat\n");
var preHash = aMethod
+ PHOTOBUCKET_PK
+ PHOTOBUCKET_SCID
+ strConcat
+ (aAuth ? this.mAuthUser.sessionkey : "");
this._logger.debug("going to sig::: " + preHash);
var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var inputStream = converter.convertToInputStream(preHash);
return FlockCryptoHash.md5Stream(inputStream);
};
// ========== END PhotobucketAPI class ==========
// ====================================================
// ========== BEGIN photobucketAccount class ==========
// ====================================================
function photobucketAccount()
{
this.acUtils = Components.classes["@flock.com/account-utils;1"]
.getService(Ci.flockIAccountUtils);
this.service = Cc[PHOTOBUCKET_CONTRACTID]
.getService(Ci.flockIMediaWebService);
this._coop = Components.classes["@flock.com/singleton;1"]
.getService(Ci.flockISingleton)
.getSingleton("chrome://flock/content/common/load-faves-coop.js")
.wrappedJSObject;
this.logger = Cc['@flock.com/logger;1'].createInstance(Ci.flockILogger);
this.logger.init("photobucket");
if (!gPhotobucketAPI) {
gPhotobucketAPI = new PhotobucketAPI();
}
this.api = gPhotobucketAPI;
this._ctk = {
interfaces: [
"nsISupports",
"flockIWebServiceAccount",
"flockIMediaWebServiceAccount",
"flockIMediaUploadAccount"
]
};
getCompTK().addAllInterfaces(this);
}
// BEGIN flockIWebServiceAccount interface
photobucketAccount.prototype.urn = null;
photobucketAccount.prototype.login =
function photobucketAccount_login(aListener)
{
this.logger.debug("{flockIWebServiceAccount}.login() urn=" + this.urn);
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Ci.nsITimer);
var inst = this;
timerFunc = {
notify: function(aTimer) {
inst.api.doLogin(inst.urn, aListener);
}
}
timer.initWithCallback(timerFunc, 0, 0); //re-check token
}
photobucketAccount.prototype.activate =
function photobucketAccount_activate(aListener)
{
this.logger.debug("{flockIWebServiceAccount}.activate() urn=" + this.urn);
var acctCoopObj = this._coop.get(this.urn);
var inst = this;
var listener = {
onSuccess: function() {
inst.logger.debug("activate() listener onAuth()");
acctCoopObj.isPollable = true;
aListener.onSuccess(inst, "accountAuthorized");
try {
var authUser = inst.api.mAuthUser;
acctCoopObj.name = authUser.fullname;
var photostreamURN = "urn:flock:stream:photo:photobucket:"+acctCoopObj.accountId;
var photostream = inst._coop.get(photostreamURN);
photostream.name = authUser.fullname+" Photostream";
} catch (ex) {
inst.logger.error(ex + '::' + ex.lineNumber);
}
},
onError: function(aError) {
inst.logger.debug("activate() listener onError()");
try {
var authUser = inst.getAuthUser();
var acctCoopObj = inst._coop.get(inst.urn);
acctCoopObj.isAuthenticated = false;
} catch (ex) {
// Don't really need to do anything, we were just trying to be nice
// anyway...
}
}
}
this.login(listener);
// Pre-emptively setting isAuthenticated to TRUE in order to avoid further
// auth attemps while this one is completing.
acctCoopObj.isAuthenticated = true;
}
photobucketAccount.prototype.deactivate =
function photobucketAccount_deactivate()
{
this.logger.debug("{flockIWebServiceAccount}.deactivate()");
var acctCoopObj = this._coop.get(this.urn);
acctCoopObj.isPollable = false;
acctCoopObj.isAuthenticated = false;
}
photobucketAccount.prototype.keep =
function photobucketAccount_keep()
{
var c_acct = this._coop.get(this.urn);
c_acct.isTransient = false;
}
// END flockIWebServiceAccount interface
// ========== END photobucketAccount class ==========